import React, {Component, PropTypes} from 'react';
import { findDOMNode } from 'react-dom';
import scrollIntoView from 'dom-scroll-into-view';
import './autocomplete.scss';
// import Request from "../request/request";
import $req from "../request/request";

class Autocomplete extends React.Component {

  static propTypes = {
    onChange: PropTypes.func,
    onSelect: PropTypes.func,
    shouldItemRender: PropTypes.func,
    sortItems: PropTypes.func,
    getItemValue: PropTypes.func,
    renderItem: PropTypes.func,
    renderMenu: PropTypes.func,
    menuStyle: PropTypes.object,
    inputProps: PropTypes.object,
    wrapperProps: PropTypes.object,
    wrapperStyle: PropTypes.object,
    placeholder: PropTypes.string,
    klass: PropTypes.string,
    requestUrl: PropTypes.string
  };

  static defaultProps = {
    wrapperProps: {},
    wrapperStyle: {
      display: 'block'
    },
    inputProps: {},
    onChange() {
    },
    onSelect(value, item) {
    },
    renderMenu(items, value, style) {
      return <div style={{...style, ...this.menuStyle}} children={items}/>
    },
    shouldItemRender() {
      return true
    },
    getItemValue(item) {
      if (!!item) {
        return item.shopName;
      }
    },
    renderItem(item, isHighlighted) {
      return <div className={isHighlighted ? "highlightedItem" : "item"} key={item.id} id={item.id}>
        <span>{item.shopName}</span>
        <span className="autocom-sp">{item.id}</span>
      </div>;
    },
    menuStyle: {
      borderRadius: '3px',
      boxShadow: '0 2px 12px rgba(0, 0, 0, 0.1)',
      background: '#fff',
      padding: '2px 0',
      fontSize: '90%',
      position: 'absolute',
      overflow: 'auto',
      maxHeight: '150px',
      zIndex: '2'
    },
    placeholder: '请输入要搜索店铺名称或ID',
    klass: 'form-control',
    requestUrl: "/account/supplier/searchShopName"
  };

  constructor(props) {
    super(props);
    this.state = {
      isOpen: false,
      highlightedIndex: null,
      value: "",
      shopItems: []
    };
  }

  componentWillMount() {
    this._ignoreBlur = false
    this._performAutoCompleteOnUpdate = false
    this._performAutoCompleteOnKeyUp = false,
      this._remeber = false
  }

  componentWillReceiveProps() {
    this._ignoreBlur = false
    this._performAutoCompleteOnUpdate = true
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.isOpen === true && prevState.isOpen === false) {
      this.setMenuPositions()
    }

    if ((this.state.isOpen && this._performAutoCompleteOnUpdate) || (this._performAutoCompleteOnUpdate && this._remeber == true)) {
      this._performAutoCompleteOnUpdate = false
      this.maybeAutoCompleteText()
    }

    this.maybeScrollItemIntoView()
  }

  maybeScrollItemIntoView() {
    if (this.state.isOpen === true && this.state.highlightedIndex !== null) {
      var itemNode = this.refs[`item-${this.state.highlightedIndex}`]
      var menuNode = this.refs.menu;
      if (itemNode == undefined || menuNode == undefined) {
        return;
      }
      scrollIntoView(
        findDOMNode(itemNode),
        findDOMNode(menuNode),
        {onlyScrollIfNeeded: true}
      )
    }
  }

  handleKeyDown(event) {
    if (this.keyDownHandlers[event.key])
      this.keyDownHandlers[event.key].call(this, event)
    else {
      const { selectionStart, value } = event.target
      if (value === this.state.value)
      // Nothing changed, no need to do anything. This also prevents
      // our workaround below from nuking user-made selections
        return
      this.setState({
        highlightedIndex: null,
        isOpen: true
      }, () => {
        // Restore caret position before autocompletion process
        // to work around a setSelectionRange bug in IE (#80)
        this.refs.input.selectionStart = selectionStart
      })
      this._remeber = false;
    }
  }

  handleChange(event) {
    this._performAutoCompleteOnKeyUp = true;
    this.setState({value: event.target.value});
    this.throttle(this.getShop, this, 500, event.target.value);
    this.props.onChangeCallback&&this.props.onChangeCallback(event.target.value);
    
  }

  throttle(method, context, time, value) {
    var delay = time || 200;
    clearTimeout(method.tId);
    method.tId = setTimeout(function () {
        method.call(context, value);
      },
      delay);
  }

  getShop(value) {
    // let settings = {
    //   method: 'GET',
    //   data: {
    //     shopName: value
    //   },
    //   success: (_json)=> {
    //     this.state.shopItems = _json;
    //     this.changeloading(this.state.shopItems);
    //   },
    //   error: (_json)=> {
    //     alert("获取失败");
    //   }
    // };
    // new Request(this.props.requestUrl, settings);

    $req.get({
      url: this.props.requestUrl,
      data: {
        shopName: value
      },
      method: 'GET',
      success:(resp)=>{
        this.state.shopItems = resp.result.list;
        this.changeloading(this.state.shopItems);
      }
    });

  }

  changeloading(items) {
    this.setState({shopItems: items})
  }

  handleKeyUp() {
    if (this._performAutoCompleteOnKeyUp) {
      this._performAutoCompleteOnKeyUp = false
      this.maybeAutoCompleteText()
    }
  }

  keyDownHandlers = {
    ArrowDown(event) {
      event.preventDefault()
      const itemsLength = this.getFilteredItems().length
      if (!itemsLength) {
        return
      }
      var { highlightedIndex } = this.state
      var index = (
      highlightedIndex === null ||
      highlightedIndex === itemsLength - 1
      ) ? 0 : highlightedIndex + 1
      this._performAutoCompleteOnKeyUp = true
      this.setState({
        highlightedIndex: index,
        isOpen: true,
      })
      this._remeber = false;
    },

    ArrowUp(event) {
      event.preventDefault()
      const itemsLength = this.getFilteredItems().length
      if (!itemsLength) {
        return
      }
      var { highlightedIndex } = this.state
      var index = (
      highlightedIndex === 0 ||
      highlightedIndex === null
      ) ? itemsLength - 1 : highlightedIndex - 1
      this._performAutoCompleteOnKeyUp = true
      this.setState({
        highlightedIndex: index,
        isOpen: true,
      })
      this._remeber = false;
    },

    Enter(event) {
      if (this.state.isOpen === false) {
        // menu is closed so there is no selection to accept -> do nothing
        return
      }
      else if (this.state.highlightedIndex == null) {
        // input has focus but no menu item is selected + enter is hit -> close the menu, highlight whatever's in input
        this.setState({
          isOpen: false
        }, () => {
          this.refs.input.select()
        })
        this._remeber = true;
      }
      else {
        // text entered + menu item has been highlighted + enter is hit -> update value to that of selected menu item, close the menu
        event.preventDefault()
        var item = this.getFilteredItems()[this.state.highlightedIndex];
        var value = this.props.getItemValue(item);
        this.setState({
          isOpen: false,
          highlightedIndex: null,
          value: value
        }, () => {
          //this.refs.input.focus() // TODO: file issue
          this.refs.input.setSelectionRange(
            value.length,
            value.length
          )
          this.props.onSelect(item)
        })
      }
    },

    Escape(event) {
      this.setState({
        highlightedIndex: null,
        isOpen: false
      })
      this._remeber = false;
    }
  }

  getFilteredItems() {
    let items = this.state.shopItems || [];
    if (items.length == 0) {
      return [];
    }
    if (this.props.shouldItemRender) {
      items = items.filter((item) => (
        this.props.shouldItemRender(item, this.state.value)
      ))
    }

    if (this.state.sortItems) {
      items.sort((a, b) => (
        this.state.sortItems(a, b, this.state.value)
      ))
    }

    return items
  }

  maybeAutoCompleteText() {
    if (this.state.value === '')
      return
    var { highlightedIndex } = this.state
    var items = this.getFilteredItems()
    if (items.length === 0)
      return
    var matchedItem = highlightedIndex !== null ?
      items[highlightedIndex] : items[0]
    var itemValue = this.props.getItemValue(matchedItem)
    var itemValueDoesMatch = (itemValue.toLowerCase().indexOf(
      this.state.value.toLowerCase()
    ) === 0)
    if (itemValueDoesMatch) {
      var node = this.refs.input
      var setSelection = () => {
        node.value = itemValue
        node.setSelectionRange(this.state.value.length, itemValue.length)
      }
      if (highlightedIndex === null)
        this.setState({highlightedIndex: 0}, setSelection)
      else
        setSelection()
    }
  }

  setMenuPositions() {
    var node = this.refs.input
    var rect = node.getBoundingClientRect()
    var computedStyle = global.window.getComputedStyle(node)
    var marginBottom = parseInt(computedStyle.marginBottom, 10) || 0;
    var marginLeft = parseInt(computedStyle.marginLeft, 10) || 0;
    var marginRight = parseInt(computedStyle.marginRight, 10) || 0;
    this.setState({
      menuTop: rect.bottom + marginBottom,
      menuLeft: rect.left + marginLeft,
      menuWidth: rect.width + marginLeft + marginRight
    })
  }

  highlightItemFromMouse(index) {
    this.setState({highlightedIndex: index})
  }

  selectItemFromMouse(item) {
    var value = this.props.getItemValue(item);
    this.setState({
      isOpen: false,
      highlightedIndex: null,
      value: value
    }, () => {
      this.props.onSelect(item)
      this.refs.input.focus()
      this.setIgnoreBlur(false)
    })
    this._remeber = false;
  }

  setIgnoreBlur(ignore) {
    this._ignoreBlur = ignore
  }

  renderMenu() {
    var items = this.getFilteredItems().map((item, index) => {
      var element = this.props.renderItem(
        item,
        this.state.highlightedIndex === index,
        {cursor: 'default'},
      )
      return React.cloneElement(element, {
        onMouseDown: () => this.setIgnoreBlur(true),
        onMouseEnter: () => this.highlightItemFromMouse(index),
        onClick: () => this.selectItemFromMouse(item),
        ref: `item-${index}`,
      })
    })
    var style = {
      minWidth: this.state.menuWidth
    }
    var menu = this.props.renderMenu(items, this.state.value, style)
    return React.cloneElement(menu, {ref: 'menu'})
  }

  handleInputBlur() {
    if (this._ignoreBlur)
      return
    this.setState({
      isOpen: false,
      highlightedIndex: null
    })
    this._remeber = false;
  }

  handleInputFocus() {
    if (this._ignoreBlur)
      return
    // We don't want `selectItemFromMouse` to trigger when
    // the user clicks into the input to focus it, so set this
    // flag to cancel out the logic in `handleInputClick`.
    // The event order is:  MouseDown -> Focus -> MouseUp -> Click
    this._ignoreClick = true
    this.setState({isOpen: true})
    this._remeber = true;
  }

  isInputFocused() {
    var el = this.refs.input
    return el.ownerDocument && (el === el.ownerDocument.activeElement)
  }

  handleInputClick() {
    // Input will not be focused if it's disabled
    if (this.isInputFocused() && this.state.isOpen === false) {
      this.setState({isOpen: true});
      this._remeber = true;
    }else if (this.state.highlightedIndex !== null && !this._ignoreClick)
      this.selectItemFromMouse(this.getFilteredItems()[this.state.highlightedIndex])
    this._ignoreClick = false
  }

  render() {
    return (
      <div style={{...this.props.wrapperStyle}} {...this.props.wrapperProps}>
        <input
          {...this.props.inputProps}
          role="combobox"
          aria-autocomplete="both"
          autoComplete="off"
          ref="input"
          onFocus={this.handleInputFocus.bind(this)}
          onBlur={this.handleInputBlur.bind(this)}
          onChange={this.handleChange.bind(this)}
          onKeyDown={this.handleKeyDown.bind(this)}
          onKeyUp={this.handleKeyUp.bind(this)}
          onClick={this.handleInputClick.bind(this)}
          value={this.state.value}
          placeholder={this.props.placeholder}
          className={this.props.klass}
        />
        {this.state.isOpen && this.renderMenu() || this._remeber && this.renderMenu()}
      </div>
    )
  }
}

export default Autocomplete;